﻿using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace System.Linq
{
    /// <summary>
    /// 	Adds behavior to System.Linq.
    /// </summary>
    public static class LinqExtensions
    {
        /// <summary>
        /// 	Eaches the specified enumeration.
        /// </summary>
        /// <typeparam name = "T"></typeparam>
        /// <param name = "source">The enumeration.</param>
        /// <param name = "action">The action.</param>
        public static void ForEach<T>(this IEnumerable<T> source, Action<T> action) {
            foreach (T item in source)
                action(item);
        }

        /// <summary>
        /// 	Toes the flat.
        /// </summary>
        /// <typeparam name = "T"></typeparam>
        /// <param name = "source">The source.</param>
        /// <param name = "childPredicate">The child predicate.</param>
        /// <returns></returns>
        public static IEnumerable<T> ToFlat<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> childPredicate) {
            foreach (T t in source) {
                yield return t;
                IEnumerable<T> children = childPredicate(t);
                if (children != null)
                    foreach (T child in ToFlat(children, childPredicate))
                        yield return child;
            }
        }

        /// <summary>
        /// 	Removes the duplicates from lists.
        /// </summary>
        /// <typeparam name = "T"></typeparam>
        /// <param name = "source">The source.</param>
        /// <returns></returns>
        public static IEnumerable<T> RemoveDuplicatesFromLists<T>(this IEnumerable source) {
            Dictionary<T, int> uniqueStore = new Dictionary<T, int>();
            Collection<T> finalList = new Collection<T>();

            foreach (T currValue in source) {
                if (uniqueStore.ContainsKey(currValue))
                    continue;

                uniqueStore.Add(currValue, 0);
                finalList.Add(currValue);
            }
            return finalList;
        }

        /// <summary>
        /// 	Finds the specified source.
        /// </summary>
        /// <typeparam name = "T"></typeparam>
        /// <param name = "source">The source.</param>
        /// <param name = "match">The match.</param>
        /// <returns></returns>
        public static T Find<T>(this IEnumerable<T> source, Predicate<T> match) {
            foreach (T item in source) {
                if (match(item))
                    return item;
            }

            return default(T);
        }

        /// <summary>
        /// 	Adds the range.
        /// </summary>
        /// <typeparam name = "T"></typeparam>
        /// <param name = "list">The list.</param>
        /// <param name = "elements">The elements.</param>
        public static void AddRange<T>(this ICollection<T> list, IEnumerable<T> elements) {
            foreach (T e in elements)
                list.Add(e);
        }
    }
}
